import { TrackOpTypes, TriggerOpTypes } from "./operations.js";

let shouldTrack = true
let activeEffect = undefined
// ITERATE_KEY这个用来指定迭代的类型
let ITERATE_KEY = Symbol('ITERATE_KEY')
const effectStack = []


// 操作映射
const operationMap = {
    [TriggerOpTypes.ADD]: [
        TrackOpTypes.ITERATE,
        TrackOpTypes.GET,
        TrackOpTypes.HAS
    ],
    [TriggerOpTypes.DELETE]: [
        TrackOpTypes.ITERATE,
        TrackOpTypes.GET,
        TrackOpTypes.HAS
    ],
    [TriggerOpTypes.SET]: [TrackOpTypes.GET]
}
const targetMap = new WeakMap()

export const pauseTrack = () => {
    shouldTrack = false
}

export const startTrack = () => {
     shouldTrack = true
}

export function track(target, type, key) {
    if(shouldTrack === false || !activeEffect) {
        return // 暂停依赖收集
    }
    let propMap = targetMap.get(target)
    if(!propMap) {
        propMap = new Map()
        targetMap.set(target, propMap)
    }
    if(type === TrackOpTypes.ITERATE) {
        key = ITERATE_KEY
    }
    let typeMap = propMap.get(key)
    if(!typeMap) {
        typeMap = new Map()
        propMap.set(key, typeMap)
    }
    let fnSet = typeMap.get(type)
    if(!fnSet) {
        fnSet = new Set()
        typeMap.set(type, fnSet)
    }
    if(!fnSet.has(activeEffect)) {
        fnSet.add(activeEffect)
        activeEffect.FnSetList.push(fnSet)
    }
}

export function trigger(target, type, key) {
   const fn =  getEffectFn(target, type, key)
    if(!fn) {
        return //都没有还派发什么更新
    }
    fn.forEach(item => {
        if(activeEffect !== item) {
            if(item.options.scheduler) {
                console.log('调度')
                item.options.scheduler(item)
            } else {
                item()
            }
        }
    })
}

export function effect(fn, options = {}) {

    const { lazy = false } = options //延迟执行的配置

    const effectFn = () => {
        try {
            activeEffect = effectFn
            // 在收集依赖前，把之前收集的依赖清掉
            effectStack.push(effect) // 执行栈解决effect 套 effect 的问题
            cleanUp(effectFn)
            return fn()
        } finally {
            effectStack.pop()
            activeEffect = effectStack[effectStack.length - 1]
        }
    }
    effectFn.FnSetList = [] //存储函数set 的数组，为cleanUp做准备
    effectFn.options = options
    if(lazy===false) {
        effectFn()
    } else {
        return effectFn
    }
}

export function cleanUp(effectFn) {
   const { FnSetList } = effectFn //拿到挂在effectFn上的数组
    if(!FnSetList.length) {
        return
    }

    for(const dep of FnSetList) { // 遍历数组取出集合
        dep.delete(effectFn) // 删除每个集合中的对应依赖函数，准备重新收集
    }
    FnSetList.length = 0 // 重新收集，也要重新收集清除list，准备下一次清除
}


function getEffectFn(target, type ,key) {
    let propMap = targetMap.get(target)
    if(!propMap) {
        return
    }

    const keys = [key]
    if(type === TriggerOpTypes.ADD || type === TriggerOpTypes.DELETE) {
        keys.push(ITERATE_KEY)
    }
    const effectFns = new Set()
    for(const key of keys) {
        const typeMap = propMap.get(key)
        if(!typeMap) {
            continue
        }
        const trackTypes = operationMap[type]
        for (const trackType of trackTypes) {
            const dep = typeMap.get(trackType)
            if(!dep) {
                continue
            }
            for(const effectFn of dep) {
                effectFns.add(effectFn)
            }
        }
    }

    return effectFns
}
